package org.dromara.crawler.mongo.mongoservice.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.mongodb.BasicDBObject;
import com.mongoplus.aggregate.Aggregate;
import com.mongoplus.aggregate.AggregateWrapper;
import com.mongoplus.aggregate.pipeline.Accumulators;
import com.mongoplus.conditions.interfaces.ConditionOperators;
import com.mongoplus.conditions.interfaces.Projection;
import com.mongoplus.conditions.query.LambdaQueryChainWrapper;
import com.mongoplus.mapping.TypeReference;
import com.mongoplus.model.PageResult;
import com.mongoplus.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.crawler.config.EdgeConfig;
import org.dromara.crawler.domain.bo.ElementEventBo;
import org.dromara.crawler.domain.vo.ElementEventVo;
import org.dromara.crawler.domain.vo.ElementTargetVo;
import org.dromara.crawler.domain.vo.GraphTimeLineVo;
import org.dromara.crawler.domain.vo.SpaceTimeLineVo;
import org.dromara.crawler.mongo.mongodomain.ElementEvent;
import org.dromara.crawler.mongo.mongodomain.ElementTarget;
import org.dromara.crawler.mongo.mongodomain.EventEventEdges;
import org.dromara.crawler.mongo.mongodomain.HotspotEvent;
import org.dromara.crawler.mongo.mongoservice.ElementEventService;
import org.dromara.crawler.mongo.mongoservice.ElementTargetService;
import org.dromara.crawler.mongo.mongoservice.EventEventEdgesService;
import org.dromara.crawler.mongo.mongoservice.HotspotEventService;
import org.dromara.crawler.utils.DocConvertUtil;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@RequiredArgsConstructor
public class ElementEventServiceImpl extends ServiceImpl<ElementEvent> implements ElementEventService {

    private final EventEventEdgesService eventEdgesService;
    private final ElementTargetService elementTargetService;

    @Override
    public Page<ElementEvent> queryByPage(ElementEventBo queryCondition, Integer pageNum, Integer pageSize) {
        PageQuery pageQuery = new PageQuery();
        // 设置默认值
        if (pageQuery.getPageNum() == null || pageQuery.getPageNum() <= 0) {
            pageQuery.setPageNum(1); // 默认第一页
        }
        if (pageQuery.getPageSize() == null || pageQuery.getPageSize() <= 0) {
            pageQuery.setPageSize(10); // 默认每页10条
        }
        Page<ElementEvent> page = pageQuery.build();
        PageResult<ElementEvent> pageResult = this.page(createWrapper(queryCondition), pageQuery.getPageNum(), pageQuery.getPageSize());
        page.setRecords(pageResult.getContentData());
        page.setTotal(pageResult.getTotalSize());  // 设置总条数
        return page;
    }

    @Override
    public List<ElementEventVo> queryEvent(String eventInfo) {
        LambdaQueryChainWrapper<ElementEvent> wrapper = this.lambdaQuery();
        if (ObjectUtil.isNotEmpty(eventInfo)) {
            LambdaQueryChainWrapper<ElementEvent> orWrapper = this.lambdaQuery();
            orWrapper.like(ElementEvent::getEventName, eventInfo);
            orWrapper.like(ElementEvent::getEventFirstLevel, eventInfo);
            orWrapper.like(ElementEvent::getEventSecondLevel, eventInfo);
            wrapper.or(orWrapper);
        }
        AggregateWrapper elementEventAggregate = new AggregateWrapper();
        elementEventAggregate
            .match(wrapper)
            .project(Projection.builder().display("event_id", "event_name", "time_position_moment").buildList())
            .sortDesc("time_position_moment");
        List<ElementEventVo> list = execute("element_event", elementEventAggregate, ElementEventVo.class);
        return list;
    }

    @Override
    public Object getSpaceTimeLineStatistics(ElementEventBo queryCondition) {
        List<String> timeList = new ArrayList<>();
        LocalDateTime startTime;
        LocalDateTime endTime;
        // 如果 startTime 或 endTime 为空，默认设置为近半年
        if (ObjectUtil.isEmpty(queryCondition.getStartTime()) || ObjectUtil.isEmpty(queryCondition.getEndTime())) {
            endTime = LocalDateTime.now().plusMonths(1); // 当前时间
            startTime = endTime.minusMonths(6); // 半年前
        } else {
            // 如果时间不为空，则使用传入的时间
            startTime = LocalDateTime.parse(queryCondition.getStartTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            endTime = LocalDateTime.parse(queryCondition.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        }
        Date startDate = Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant());
        Date endDate = Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant());
/*        long monthsBetween = ChronoUnit.MONTHS.between(startTime, endTime);
        if (monthsBetween < 1) {
            // 1个月：按天
            while (!startTime.isAfter(endTime)) {
                timeList.add(startTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                startTime = startTime.plusDays(1);
            }
        } else {
            // 3个月、6个月、1年：按月
            while (!startTime.isAfter(endTime)) {
                timeList.add(startTime.format(DateTimeFormatter.ofPattern("yyyy-MM")));
                startTime = startTime.plusMonths(1);
            }
        }*/
//        while (!startTime.isAfter(endTime)) {
//            timeList.add(startTime.format(DateTimeFormatter.ofPattern("yyyy-MM")));
//            startTime = startTime.plusMonths(1);
//        }
        LocalDateTime tempStartTime = startTime;
        while (!tempStartTime.isAfter(endTime)) {
            timeList.add(tempStartTime.format(DateTimeFormatter.ofPattern("yyyy-MM")));
            tempStartTime = tempStartTime.plusMonths(1);
        }
        // Element_Event数据
        AggregateWrapper elementEventAggregate = new AggregateWrapper();
        LambdaQueryChainWrapper<ElementEvent> wrapper = createWrapper(queryCondition);
        wrapper.lt(ElementEvent::getTimePositionMoment, endDate);
        wrapper.gte(ElementEvent::getTimePositionMoment, startDate);
        elementEventAggregate.project(Projection.builder().display("event_id", "event_name", "time_position_moment", "space_position_coordinate", "emotion_characteristics","event_first_level","event_second_level","space_position_region","relationship_characteristics_subject_person","relationship_characteristics_related_party_person").buildList());
/*        if (monthsBetween < 1) {
            elementEventAggregate.match(wrapper)
                .addFields(new BasicDBObject("type", "1"))
                .sortAsc("time_position_moment")
                .group(ConditionOperators.dateToString("%Y-%m-%d", "$time_position_moment"), Accumulators.push("docs", "$$ROOT"));
        } else {
            elementEventAggregate.match(wrapper)
                .addFields(new BasicDBObject("type", "1"))
                .sortAsc("time_position_moment")
                .group(ConditionOperators.dateToString("%Y-%m", "$time_position_moment"), Accumulators.push("docs", "$$ROOT"));
        }*/
        elementEventAggregate.match(wrapper)
            .addFields(new BasicDBObject("type", "1"))
            .sortAsc("time_position_moment")
            .group(ConditionOperators.dateToString("%Y-%m", "$time_position_moment"), Accumulators.push("docs", "$$ROOT"));
        elementEventAggregate.sortAsc("_id");
        List<Document> documentList = execute("element_event", elementEventAggregate, Document.class);
        Map<String, List<ElementEventVo>> timePointMap = documentList.stream()
            .collect(Collectors.toMap(
                d -> d.getString("_id"),
                d -> DocConvertUtil.toEntityList(d.getList("docs", Document.class), ElementEventVo.class)
            ));
        List<SpaceTimeLineVo> result = new ArrayList<>();
        timeList.stream().forEach(t -> {
            SpaceTimeLineVo spaceTimeLineVo = new SpaceTimeLineVo();
            List<ElementEventVo> docs = timePointMap.get(t);
            spaceTimeLineVo.setDate(t);
            if (ObjectUtil.isNotEmpty(docs)) {
                spaceTimeLineVo.setData(docs);
            } else {
                spaceTimeLineVo.setData(new ArrayList<>());
            }
            result.add(spaceTimeLineVo);
        });
        return result;
    }

    @Override
    public Object getGraphTimeLineStatistics(ElementEventBo queryCondition) {
        List<String> timeList = new ArrayList<>();
        LocalDateTime startTime;
        LocalDateTime endTime;

        // 如果 startTime 或 endTime 为空，默认设置为近半年
        if (ObjectUtil.isEmpty(queryCondition.getStartTime()) || ObjectUtil.isEmpty(queryCondition.getEndTime())) {
            endTime = LocalDateTime.now().plusMonths(1); // 当前时间
            startTime = endTime.minusMonths(6); // 半年前
        } else {
            // 如果时间不为空，则使用传入的时间
            startTime = LocalDateTime.parse(queryCondition.getStartTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            endTime = LocalDateTime.parse(queryCondition.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).plusMonths(1);
        }

        Date startDate = Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant());
        Date endDate = Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant());

        while (!startTime.isAfter(endTime)) {
            timeList.add(startTime.format(DateTimeFormatter.ofPattern("yyyy-MM")));
            startTime = startTime.plusMonths(1);
        }

        AggregateWrapper elementEventAggregate = new AggregateWrapper();
        LambdaQueryChainWrapper<ElementEvent> wrapper = createWrapper(queryCondition);
        wrapper.lt(ElementEvent::getTimePositionMoment, endDate);
        wrapper.gte(ElementEvent::getTimePositionMoment, startDate);

        elementEventAggregate.project(Projection.builder().display("event_id", "event_name", "time_position_moment", "space_position_coordinate", "emotion_characteristics", "event_first_level", "event_second_level", "space_position_region", "relationship_characteristics_subject_person", "relationship_characteristics_related_party_person").buildList());

        elementEventAggregate.match(wrapper)
            .addFields(new BasicDBObject("type", "1"))
            .sortAsc("time_position_moment")
            .group(ConditionOperators.dateToString("%Y-%m", "$time_position_moment"), Accumulators.push("docs", "$$ROOT"));

        elementEventAggregate.sortAsc("_id");
        List<Document> documentList = execute("element_event", elementEventAggregate, Document.class);

        Map<String, List<ElementEventVo>> timePointMap = documentList.stream()
            .collect(Collectors.toMap(
                d -> d.getString("_id"),
                d -> DocConvertUtil.toEntityList(d.getList("docs", Document.class), ElementEventVo.class)
            ));

        // 查询边
        List<String> eventIds = timePointMap.values().stream()
            .flatMap(List::stream)
            .map(ElementEventVo::getEventId)
            .collect(Collectors.toList());

        Map<String, List<EventEventEdges>> edgesMap = eventEdgesService.getRelation(eventIds);

        // 事件全集：便于全局判断 id 是否为事件
        Map<String, ElementEventVo> allEventMap = timePointMap.values().stream()
            .flatMap(List::stream)
            .collect(Collectors.toMap(ElementEventVo::getEventId, e -> e, (a, b) -> a));

        // 从 edgesMap 里收集所有参与关系的 id（包含事件和目标）
        Set<String> idsAppearedInEdges = edgesMap.values().stream()
            .filter(Objects::nonNull)
            .flatMap(List::stream)
            .flatMap(edge -> Stream.of(edge.getSrc(), edge.getDst()))
            .collect(Collectors.toCollection(LinkedHashSet::new));

        // 目标 id = 边里出现过的 id - 事件 id
        Set<String> allTargetIds = idsAppearedInEdges.stream()
            .filter(id -> !id.startsWith("Th"))
            .collect(Collectors.toSet());

        // 查询所有目标信息
        Map<String, ElementTarget> globalTargetMap = elementTargetService.queryListByTargetIds(new ArrayList<>(allTargetIds))
            .stream()
            .collect(Collectors.toMap(ElementTarget::getTargetId, t -> t));

        List<GraphTimeLineVo> resultList = new ArrayList<>();

        // 记录所有缺失的事件 ID
        Set<String> missingEventIds = new HashSet<>();

        // 遍历每个月份（时间点）
        for (String t : timeList) {
            GraphTimeLineVo graphTimeLineVo = new GraphTimeLineVo();
            graphTimeLineVo.setDate(t);

            JSONObject jsonObject = new JSONObject();
            JSONArray nodes = new JSONArray();
            JSONArray links = new JSONArray();

            jsonObject.set("rootId", "");
            jsonObject.set("nodes", nodes);
            jsonObject.set("links", links);

            // 当前时间片内的事件
            List<ElementEventVo> elementEventVos = timePointMap.get(t);
            Set<String> nodeIdsOrdered = new LinkedHashSet<>();

            // 1) 先处理所有边，收集链接
            processEdgesForTimePoint(edgesMap, elementEventVos, allEventMap, globalTargetMap, links, nodeIdsOrdered);

            // 2) 填充节点数据
            processNodesForTimePoint(nodeIdsOrdered, allEventMap, globalTargetMap, missingEventIds, nodes);

            // 3) 过滤无边节点（保险起见，虽然按 links 造的 nodes 理论上已无孤点）
            filterNodesByLinks(nodes, links);

            // 4) 选择 rootId：优先选“事件”，再退而求其次
            String rootId = nodeIdsOrdered.stream()
                .filter(allEventMap::containsKey)
                .findFirst()
                .orElse(nodeIdsOrdered.stream().findFirst().orElse(""));

            jsonObject.set("rootId", rootId);
            jsonObject.set("nodes", nodes);
            jsonObject.set("links", links);

            graphTimeLineVo.setData(jsonObject);
            resultList.add(graphTimeLineVo);
        }

        // 批量查询缺失的事件并填充
        if (!missingEventIds.isEmpty()) {
            List<ElementEvent> missingEvents = queryListByEventIds(new ArrayList<>(missingEventIds));
            Map<String, ElementEventVo> missingEventMap = missingEvents.stream()
                .collect(Collectors.toMap(ElementEvent::getEventId, this::convertToElementEventVo));

            // 将缺失事件的数据加入到 allEventMap 中
            allEventMap.putAll(missingEventMap);

            // 更新所有已经处理的节点
            updateNodesWithMissingEvents(resultList, missingEventMap);
        }

        return resultList;
    }

    // 转换 ElementEvent 到 ElementEventVo（只需要赋值 eventName）
    private ElementEventVo convertToElementEventVo(ElementEvent elementEvent) {
        // 假设只需要赋值 eventName
        ElementEventVo vo = new ElementEventVo();
        vo.setEventId(elementEvent.getEventId());
        vo.setEventName(elementEvent.getEventName());
        return vo;
    }

    // 处理时间点的边
    private void processEdgesForTimePoint(Map<String, List<EventEventEdges>> edgesMap, List<ElementEventVo> elementEventVos,
                                          Map<String, ElementEventVo> allEventMap, Map<String, ElementTarget> globalTargetMap,
                                          JSONArray links, Set<String> nodeIdsOrdered) {
        if (ObjectUtil.isNotEmpty(elementEventVos)) {
            for (ElementEventVo ev : elementEventVos) {
                List<EventEventEdges> es = edgesMap.get(ev.getEventId());
                if (ObjectUtil.isNotEmpty(es)) {
                    for (EventEventEdges edge : es) {
                        // 确保每一条 link 的 from 和 to 对应的节点存在
                        if (allEventMap.containsKey(edge.getSrc()) || globalTargetMap.containsKey(edge.getSrc())) {
                            JSONObject link = new JSONObject();
                            link.set("from", edge.getSrc());
                            link.set("to", edge.getDst());
                            if (EdgeConfig.edgeConstantMap.containsKey(edge.getRelation())) {
                                link.set("text", EdgeConfig.edgeConstantMap.get(edge.getRelation()).getCname());
                            }
                            links.put(link);

                            // 确保 src 和 dst 都添加到 nodeIdsOrdered 中
                            nodeIdsOrdered.add(edge.getSrc());
                            nodeIdsOrdered.add(edge.getDst());
                        }
                    }
                }
            }
        }
    }

    // 处理时间点的节点
    private void processNodesForTimePoint(Set<String> nodeIdsOrdered, Map<String, ElementEventVo> allEventMap,
                                          Map<String, ElementTarget> globalTargetMap, Set<String> missingEventIds,
                                          JSONArray nodes) {
        for (String id : nodeIdsOrdered) {
            JSONObject node = new JSONObject();
            node.set("id", id);

            if (allEventMap.containsKey(id)) {
                node.set("text", allEventMap.get(id).getEventName());
                node.set("type", "event");
            } else if (globalTargetMap.containsKey(id)) {
                ElementTarget target = globalTargetMap.get(id);
                String name = ObjectUtil.isNotEmpty(target.getName()) ? target.getName() : id;
                node.set("text", name);
                node.set("type", "target");
            } else {
                // 如果事件不在记录中，标记缺失的事件 ID
                missingEventIds.add(id);
                node.set("text", "Unknown");
                node.set("type", "unknown");  // 设置未知类型的节点
            }
            nodes.put(node);
        }
    }

    // 更新节点数据（填充缺失事件）
    private void updateNodesWithMissingEvents(List<GraphTimeLineVo> resultList, Map<String, ElementEventVo> missingEventMap) {
        resultList.forEach(graphTimeLineVo -> {
            JSONObject jsonObject = graphTimeLineVo.getData();
            JSONArray nodes = jsonObject.getJSONArray("nodes");
            for (int i = 0; i < nodes.size(); i++) {
                JSONObject node = nodes.getJSONObject(i);
                String eventId = node.getStr("id");

                // 更新节点数据
                if (missingEventMap.containsKey(eventId)) {
                    ElementEventVo missingEvent = missingEventMap.get(eventId);
                    node.put("text", missingEvent.getEventName());
                    node.put("type", "event");
                }
            }
        });
    }

    @Override
    public ElementEvent queryEventById(String id) {
        return this.getById(id);
    }

    @Override
    public List<ElementEvent> queryRelatedEvent(String targetId) {
        List<EventEventEdges> edges = eventEdgesService.getEdgesByTargetId(targetId);
        List<String> srcIds = edges.stream().map(EventEventEdges::getSrc).collect(Collectors.toList());
        List<String> dstIds = edges.stream().map(EventEventEdges::getDst).collect(Collectors.toList());
        List<String> eventIds = new ArrayList<>();
        eventIds.addAll(srcIds);
        eventIds.addAll(dstIds);
        return this.lambdaQuery().in(ElementEvent::getEventId, eventIds).list();
    }

    @Override
    public List<ElementEvent> queryListByEventIds(List<String> eventIds) {
        LambdaQueryChainWrapper<ElementEvent> wrapper = this.lambdaQuery();
        wrapper.in(ElementEvent::getEventId, eventIds);
        return list(wrapper);
    }

    @Override
    public JSONObject queryObjectByTargetId(String targetId) {
        List<EventEventEdges> edges = eventEdgesService.getEdgesByTargetId(targetId);
        List<String> srcIds = edges.stream().map(EventEventEdges::getSrc).collect(Collectors.toList());
        List<String> dstIds = edges.stream().map(EventEventEdges::getDst).collect(Collectors.toList());
        List<String> eventIds = new ArrayList<>();
        eventIds.addAll(srcIds);
        eventIds.addAll(dstIds);
        List<ElementEvent> eventList = this.queryListByEventIds(eventIds);
        List<ElementTarget> targetList = elementTargetService.queryListByTargetIds(eventIds);
        List<JSONObject> dataList = new ArrayList<>();
        List<JSONObject> linkList = new ArrayList<>();
        eventList.stream().forEach(event -> {
            JSONObject dataObject = new JSONObject();
            dataObject.set("id", event.getEventId());
            dataObject.set("name", event.getEventName());
            dataObject.set("type", "event");
            dataObject.set("coordinate", event.getSpacePositionCoordinate());
            dataList.add(dataObject);
        });
        targetList.stream().forEach(target -> {
            JSONObject dataObject = new JSONObject();
            dataObject.set("id", target.getTargetId());
            dataObject.set("name", target.getName());
            dataObject.set("type", "target");
            dataObject.set("coordinate", target.getCoordinate());
            dataList.add(dataObject);
        });

        edges.stream().forEach(edge -> {
            JSONObject linkObject = new JSONObject();
            if (edge.getSrc().equals(targetId)) {
                linkObject.set("source", targetId);
                linkObject.set("target", edge.getDst());
            } else if (edge.getDst().equals(targetId)) {
                linkObject.set("source", edge.getSrc());
                linkObject.set("target", targetId);
            } else {
                //什么也不干
            }
            if (EdgeConfig.edgeConstantMap.containsKey(edge.getRelation())) {
                linkObject.set("value", EdgeConfig.edgeConstantMap.get(edge.getRelation()).getCname());
            }
            linkList.add(linkObject);
        });
        JSONObject resultObject = new JSONObject();
        resultObject.set("data", dataList);
        resultObject.set("links", linkList);
        return resultObject;
    }

    @Override
    public Object queryEventGroup(String eventInfo) {
        LambdaQueryChainWrapper<ElementEvent> wrapper = this.lambdaQuery();
        wrapper.ne(ElementEvent::getStatus, "-1");
        if (ObjectUtil.isNotEmpty(eventInfo)) {
            LambdaQueryChainWrapper<ElementEvent> orWrapper = this.lambdaQuery();
            orWrapper.like(ElementEvent::getEventName, eventInfo);
            orWrapper.like(ElementEvent::getEventFirstLevel, eventInfo);
            orWrapper.like(ElementEvent::getEventSecondLevel, eventInfo);
            wrapper.or(orWrapper);
        }
        AggregateWrapper elementEventAggregate = new AggregateWrapper();
        elementEventAggregate.project(Projection.builder().display("_id", "event_id", "event_name", "event_first_level", "event_second_level", "time_position_moment", "space_position_coordinate", "emotion_characteristics","status").buildList());
        elementEventAggregate.match(wrapper)
            .addFields(new BasicDBObject("type", "1"))
            .group("$event_first_level", Accumulators.push("docs", "$$ROOT"));
        elementEventAggregate.sortAsc("_id");
        List<Document> documentList = execute("element_event", elementEventAggregate, Document.class);
        Map<String, List<ElementEventVo>> elementMap = documentList.stream()
            .collect(Collectors.toMap(
                d -> d.getString("_id"),
                d -> DocConvertUtil.toEntityList(d.getList("docs", Document.class), ElementEventVo.class)
            ));
        return elementMap;
    }

    @Override
    public List<ElementEventVo> queryEventByEventIds(List<String> eventIds) {
        AggregateWrapper elementEventAggregate = new AggregateWrapper();
        LambdaQueryChainWrapper<ElementEvent> wrapper = this.lambdaQuery();
        wrapper.in(ElementEvent::getEventId, eventIds);
        elementEventAggregate.project(Projection.builder().display("event_id", "event_name", "space_position_coordinate").buildList());
        elementEventAggregate.match(wrapper);
        return execute("element_event", elementEventAggregate, ElementEventVo.class);
    }


    private LambdaQueryChainWrapper<ElementEvent> createWrapper(ElementEventBo queryCondition) {
        LambdaQueryChainWrapper<ElementEvent> wrapper = this.lambdaQuery();
        // 基础等值
        wrapper.eq(ObjectUtil.isNotEmpty(queryCondition.getEventFirstLevel()),ElementEvent::getEventFirstLevel,  queryCondition.getEventFirstLevel())
            .eq(ObjectUtil.isNotEmpty(queryCondition.getEventSecondLevel()),ElementEvent::getEventSecondLevel, queryCondition.getEventSecondLevel())
            .eq(ObjectUtil.isNotEmpty(queryCondition.getEmotion()),ElementEvent::getEmotionCharacteristics, queryCondition.getEmotion());
        if (ObjectUtil.isNotEmpty(queryCondition.getPerson())) {
            wrapper.and(w -> w.or(inner -> inner
                .like(ElementEvent::getRelationshipCharacteristicsSubjectPerson, queryCondition.getPerson())
                .like(ElementEvent::getRelationshipCharacteristicsRelatedPartyPerson, queryCondition.getPerson())
            ));
        }
        if (ObjectUtil.isNotEmpty(queryCondition.getLocation())) {
            wrapper.and(w -> w.or(inner -> inner
                .like(ElementEvent::getSpacePositionRegion,queryCondition.getLocation())
                .like(ElementEvent::getSpacePositionPlaceName,queryCondition.getLocation())
            ));
        }
        // 事件名模糊
        wrapper.like(ObjectUtil.isNotEmpty(queryCondition.getEventName()), ElementEvent::getEventName, queryCondition.getEventName());
        // 排序
        wrapper.orderByAsc(ElementEvent::getTimePositionMoment);
        return wrapper;
    }


    private List<Map<String, Object>> execute(String collectionName, Aggregate<?> aggregate) {
        return baseMapper.aggregateList(collectionName, aggregate, new TypeReference<Map<String, Object>>() {
        });
    }


    private <T> List<T> execute(String collectionName, Aggregate<?> aggregate, Class<T> clazz) {
        return baseMapper.aggregateList(collectionName, aggregate, clazz);
    }

    /**
     * 根据 links 过滤 nodes:
     * - 如果 links 为空，则清空所有 nodes
     * - 否则只保留出现在 links 中 (from/to) 的节点
     */
    private void filterNodesByLinks(JSONArray nodes, JSONArray links) {
        if (ObjectUtil.isNotEmpty(links)) {
            // 收集所有 link 中的 from/to 节点 id
            Set<String> linkedNodeIds = new HashSet<>();
            for (int i = 0; i < links.size(); i++) {
                JSONObject link = links.getJSONObject(i);
                linkedNodeIds.add(link.getStr("from"));
                linkedNodeIds.add(link.getStr("to"));
            }

            // 过滤掉没有出现在 link 里的节点
            JSONArray filteredNodes = new JSONArray();
            for (int i = 0; i < nodes.size(); i++) {
                JSONObject node = nodes.getJSONObject(i);
                if (linkedNodeIds.contains(node.getStr("id"))) {
                    filteredNodes.put(node);
                }
            }

            // 清空 nodes 再放入过滤后的节点
            nodes.clear();
            for (int i = 0; i < filteredNodes.size(); i++) {
                nodes.put(filteredNodes.getJSONObject(i));
            }
        } else {
            // 如果没有任何 links，清空所有节点
            nodes.clear();
        }
    }

}
